// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.

package tests.detailed.handler;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import org.cef.callback.CefCallback;
import org.cef.handler.CefResourceHandlerAdapter;
import org.cef.misc.IntRef;
import org.cef.misc.StringRef;
import org.cef.network.CefRequest;
import org.cef.network.CefResponse;

/**
 * The example for the second scheme with domain handling is a more
 * complex example and is taken from the parent project CEF. Please
 * see CEF: "cefclient/scheme_test.cpp" for futher details
 */
public class ClientSchemeHandler extends CefResourceHandlerAdapter {
  public static final String scheme = "client";
  public static final String domain = "tests";

  private byte[] data_;
  private String mime_type_;
  private int offset_ = 0;

  public ClientSchemeHandler() {
    super();
  }

  @Override
  public synchronized boolean processRequest(CefRequest request, CefCallback callback) {
    boolean handled = false;
    String url = request.getURL();
    if (url.indexOf("handler.html") != -1) {
      // Build the response html
      String html;
      html = "<html><head><title>Client Scheme Handler</title></head>" +
             "<body bgcolor=\"white\">" +
             "This contents of this page page are served by the " +
             "ClientSchemeHandler class handling the client:// protocol." +
             "<br/>You should see an image:" +
             "<br/><img src=\"client://tests/logo.png\"><pre>";

      // Output a string representation of the request
      html += request.toString();

      html += "</pre><br/>Try the test form:" +
              "<form method=\"POST\" action=\"handler.html\">" +
              "<input type=\"text\" name=\"field1\">" +
              "<input type=\"text\" name=\"field2\">" +
              "<input type=\"submit\">" +
              "</form></body></html>";

      data_ = html.getBytes();

      handled = true;
      // Set the resulting mime type
      mime_type_ = "text/html";
    } else if (url.endsWith(".png")) {
      handled = loadContent(url.substring(url.lastIndexOf('/')+1));
      mime_type_ = "image/png";
    } else if (url.endsWith(".html")) {
      handled = loadContent(url.substring(url.lastIndexOf('/')+1));
      mime_type_ = "text/html";
      if (!handled) {
        String html = "<html><head><title>Error 404</title></head>";
               html+= "<body><h1>Error 404</h1>";
               html+= "File  " + url.substring(url.lastIndexOf('/')+1) + " ";
               html+= "does not exist</body></html>";
        data_ = html.getBytes();
        handled = true;
      }
    }

    if (handled) {
      // Indicate the headers are available.
      callback.Continue();
      return true;
    }

    return false;
  }

  @Override
  public void getResponseHeaders(CefResponse response,
                                 IntRef response_length,
                                 StringRef redirectUrl) {
    response.setMimeType(mime_type_);
    response.setStatus(200);

    // Set the resulting response length
    response_length.set(data_.length);
  }

  @Override
  public synchronized boolean readResponse(byte[] data_out,
                              int bytes_to_read,
                              IntRef bytes_read,
                              CefCallback callback) {
    boolean has_data = false;

    if (offset_ < data_.length) {
      // Copy the next block of data into the buffer.
      int transfer_size = Math.min(bytes_to_read, (data_.length - offset_));
      System.arraycopy(data_, offset_, data_out, 0, transfer_size);
      offset_ += transfer_size;

      bytes_read.set(transfer_size);
      has_data = true;
    } else {
      offset_ = 0;
      bytes_read.set(0);
    }

    return has_data;
  }

  private boolean loadContent(String resName) {
    InputStream inStream = getClass().getResourceAsStream(resName);
    if (inStream != null) {
      try {
        ByteArrayOutputStream outFile = new ByteArrayOutputStream();
        int readByte = -1;
        while ((readByte = inStream.read()) >= 0)
          outFile.write(readByte);
        data_ = outFile.toByteArray();
        return true;
      } catch (IOException e) { }
    }
    return false;
  }
}
